/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package treccontextsug;

/**
 *
 * @author manzato
 */
/**
 * A simple example of an in-memory search using Lucene.
 */
import java.io.IOException;
import java.io.StringReader;

import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.Query;
import org.apache.lucene.document.Field;
import org.apache.lucene.search.Searcher;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.document.Document;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.analysis.standard.StandardAnalyzer;

public class LuceneSearch {

    private RAMDirectory idx;
    private IndexWriter writer;
    private Searcher searcher;

    public LuceneSearch() {
        idx = new RAMDirectory();
        try {
            writer = new IndexWriter(idx, new StandardAnalyzer(), true);
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }

    public void addDocument(String docId, String url, String title, String description, String baseNames, String indexedText) {
        try {
            writer.addDocument(createDocument(docId, url, title, description, baseNames, indexedText));
        } catch (IOException ex) {
            Logger.getLogger(LuceneSearch.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void optimize() {
        try {
            writer.optimize();
            writer.close();
            searcher = new IndexSearcher(idx);            
        } catch (IOException ex) {
            Logger.getLogger(LuceneSearch.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void close() {
        try {
            searcher.close();
        } catch (IOException ex) {
            Logger.getLogger(LuceneSearch.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Make a Document object with an un-indexed title field and an
     * indexed content field.
     */
    private static Document createDocument(String docId, String url, String title, String description, String baseNames, String indexedText) {
        Document doc = new Document();

        // Add the metadata as an unindexed field...
        doc.add(Field.UnIndexed("docId", docId));
        doc.add(Field.UnIndexed("url", url));
        doc.add(Field.UnIndexed("title", title));
        doc.add(Field.UnIndexed("description", description));
        doc.add(Field.UnIndexed("baseNames", baseNames));

        // ...and the content as an indexed field. Note that indexed
        // Text fields are constructed using a Reader. Lucene can read
        // and index very large chunks of text, without storing the
        // entire content verbatim in the index. In this example we
        // can just wrap the content string in a StringReader.
        doc.add(Field.Text("content", new StringReader(indexedText)));

        return doc;
    }

    /**
     * Searches for the given string in the "content" field
     */
    public Result[] search(String queryString) {
        Result[] res = null;
        // Build a Query object
        Query query;
        try {
            String filteredQuery = queryString.toLowerCase().replaceAll("[^a-z]", " ");
            query = QueryParser.parse(filteredQuery, "content", new StandardAnalyzer());
            Hits hits;
            hits = searcher.search(query);
            int hitCount = hits.length();
            res = new Result[hitCount];
            if (hitCount == 0) {
                return null;
            } else {
                // Iterate over the Documents in the Hits object
                for (int i = 0; i < hitCount; i++) {
                    Document doc = hits.doc(i);

                    // Print the value that we stored in the "title" field. Note
                    // that this Field was not indexed, but (unlike the
                    // "contents" field) was stored verbatim and can be
                    // retrieved.
                    res[i] = new Result(hits.score(i), doc.get("docId"), doc.get("url"), doc.get("title"), doc.get("description"));
                }
            }
        } catch (ParseException ex) {
            if (ex.getMessage().equalsIgnoreCase("Too many boolean clauses")) {
                return search(queryString.substring(0, 40));
            } else {
                System.err.println("Query string not parsed: " + queryString);
                return null;
            }
        } catch (IOException e) {
            Logger.getLogger(LuceneSearch.class.getName()).log(Level.SEVERE, null, e);
        }
        return res;
    }
}
